package com.googlewell.zelix.analy;

import com.googlewell.zelix.model.Zelix;
import com.googlewell.zelix.test.SearchTest;
import com.googlewell.zelix.tool.ClassTool;
import com.googlewell.zelix.tool.SearchTool;
import me.coley.recaf.control.Controller;
import me.coley.recaf.search.*;
import me.coley.recaf.util.OpcodeUtil;
import me.coley.recaf.workspace.JavaResource;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;

import java.util.ArrayList;
import java.util.HashSet;

public class ZelixAnaly {
    public static void analy(Controller controller, JavaResource resource) {
        analyZelixMain(controller);
        analyDataInputStream(controller);
    }

    /**
     * 分析ZKM的main方法,该方法固定,从主入口分析InvokeDynamic的外部处理类,分析long值计算和保存的接口和类
     *
     * @param controller
     */
    public static void analyZelixMain(Controller controller) {
        Zelix zelix = new Zelix(controller);

        //分析InvokeDynamic指令
        InvokeDynamicInsnNode innerInvokeDynamic = zelix.getInnerInvokeDynamic();
        if (innerInvokeDynamic != null) {
            System.out.println("本类内处理:" + innerInvokeDynamic.name + ":" + innerInvokeDynamic.desc + ":" + innerInvokeDynamic.bsm.getOwner() + ":" + innerInvokeDynamic.bsm.getName() + ":" + innerInvokeDynamic.bsm.getDesc());
        }
        InvokeDynamicInsnNode outerInvokeDynamic = zelix.getOuterInvokeDynamic();
        if (outerInvokeDynamic != null) {
            System.out.println("外部类处理:" + outerInvokeDynamic.name + ":" + outerInvokeDynamic.desc + ":" + outerInvokeDynamic.bsm.getOwner() + ":" + outerInvokeDynamic.bsm.getName() + ":" + outerInvokeDynamic.bsm.getDesc());
        }


        //分析long值计算的类
        MemberResult interfaceResult = zelix.getInterfaceResult();
        if (interfaceResult != null) {
            System.out.println("接口类:" + interfaceResult.getOwner() + ":" + interfaceResult.getName() + ":" + interfaceResult.getDesc());
            //其引用类
            HashSet<String> classReferences = zelix.getClassReferences();
            System.out.println("引用类:" + classReferences);
        }
    }

    /**
     * 分析DataInputStream的子类,这个用于class文件的读取
     *
     * @param controller
     */
    public static void analyDataInputStream(Controller controller) {
        //搜索java/io/DataInputStream的子类
        ArrayList<String> childs = new ArrayList<>();
        controller.getWorkspace().getHierarchyGraph().getVertex("java/io/DataInputStream").getDirectedChildren().forEach(v -> childs.add(v.toString()));
        if (childs.size() == 1) {
            System.out.println("java.io.DataInputStream的子类:" + childs.get(0));
        } else {
            System.out.println("获取java.io.DataInputStream子类异常,子类个数:" + childs.size());
        }

        //查询值,-889275714为java的class文件魔数0xcafebabe
        SearchCollector searchCollector = SearchTool.searchValue(controller.getWorkspace(), -889275714, new ArrayList<>());

        if (searchCollector.getAllResults().size() == 2) {//两个类,一个读,一个写
            for (SearchResult result : searchCollector.getAllResults()) {
                if (result instanceof ValueResult) {
                    ValueResult valueResult = (ValueResult) result;
                    if (valueResult.getContext() instanceof Context.InsnContext) {
                        Context.InsnContext insnContext = (Context.InsnContext) valueResult.getContext();
                        AbstractInsnNode node = insnContext.getInsn();
                        if (node.getNext().getOpcode() == Opcodes.ALOAD && node.getPrevious().getOpcode() == Opcodes.ILOAD) {//读的情况,zkm8、zkm15、zkm17都符合
                            System.out.println("读class文件:" + ClassTool.getClassContext(insnContext) + " " + insnContext.getParent().getName() + " " + insnContext.getParent().getDesc());
                        } else {
                            System.out.println("写class文件:" + ClassTool.getClassContext(insnContext) + " " + insnContext.getParent().getName() + " " + insnContext.getParent().getDesc());
                        }
                    }
                }
            }
        }
    }
}
